package sm.div;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.orm.hibernate3.HibernateTemplate;

import sm.dam.api.DBDictService;
import sm.dbdict.DBDictUtil;
import sm.dbdict.def.DBDict;
import sm.dbdict.def.Field;
import sm.div.api.JoinValidator;
import sm.util.SMMap;
import sm.util.Util;

import com.google.gson.Gson;

public class JoinValidatorImpl implements JoinValidator {

	private static Logger logger = LoggerFactory.getLogger(JoinValidator.class);

	private HibernateTemplate template;

	public JoinValidatorImpl(ApplicationContext context) {
		template = (HibernateTemplate) context.getBean("template");
	}

	private DBDict getDBDict(String fileName) {
		DBDict des = null;
		Object dbdict = template.get(DBDictService.DBDICT, fileName);
		if (dbdict != null) {
			SMMap dbdictMap = (SMMap) dbdict;
			des = (DBDict) dbdictMap.get(DBDictService.DESCRIPTOR);
		}
		return des;
	}

	@Override
	public void validateJoin() {
		Gson gson = new Gson();

		// check unmatched joindef
		List<Object> joindefs = template.find("from joindefs");
		for (Object joindef : joindefs) {
			SMMap joindefMap = (SMMap) joindef;
			String joinName = (String) joindefMap.get("join_name");
			List<SMMap> joinTables = (List<SMMap>) joindefMap
					.get("join_tables");
			int size = joinTables.size();
			String[] files = new String[size];
			for (int i = 0; i < size; i++) {
				SMMap joinTable = joinTables.get(i);
				String file = (String) joinTable.get("table_name");
				files[i] = file;
			}

			if (size != 2) {
				logger.warn("Unmatched joindefs " + joinName + ": "
						+ gson.toJson(files));
			} else {
				String file1 = files[0];
				String file2 = files[1];

				List<Object> erddef = template.find(
						"from erddef where file1 = ? and file2 = ?",
						new String[] { file1, file2 });
				if (erddef == null || erddef.size() == 0) {
					logger.warn("Unmatched joindefs " + joinName + ": "
							+ gson.toJson(files));
				}
			}
		}

		// check unmatched erddef
		List<Object> erddefs = template.find("from erddef");
		for (Object erddef : erddefs) {
			SMMap erddefMap = (SMMap) erddef;
			Object file1 = erddefMap.get("file1");
			Object file2 = erddefMap.get("file2");
			List<String> file1Names = (List<String>) erddefMap
					.get("file1_names");
			List<String> file2Names = (List<String>) erddefMap
					.get("file2_names");
			if (Util.isNull(file1) || Util.isNull(file2)) {
				logger.warn("Unmatched erddef: " + gson.toJson(file1)
						+ " join " + gson.toJson(file2));
			} else {
				DBDict dbdict1 = getDBDict((String) file1);
				DBDict dbdict2 = getDBDict((String) file2);

				if (dbdict1 == null || dbdict2 == null) {
					logger.warn("Unmatched erddef: " + file1 + " join " + file2);
				} else if (file1Names.size() != file2Names.size()) {
					logger.warn("Unmatched erddef: " + file1 + "("
							+ gson.toJson(file1Names) + ") join " + file2 + "("
							+ gson.toJson(file2Names) + ")");
				} else {
					int size = file1Names.size();
					for (int i = 0; i < size; i++) {
						String file1Name = file1Names.get(i);
						String file2Name = file2Names.get(i);
						Field field1 = DBDictUtil.getField(file1Name,
								dbdict1.getField());
						Field field2 = DBDictUtil.getField(file2Name,
								dbdict2.getField());
						if (field1 == null || field2 == null) {
							logger.warn("Unmatched erddef: ");
							logger.warn(file1 + ": " + file1Name);
							logger.warn(file2 + ": " + file2Name);
							break;
						} else if (field1.getType() != field2.getType()) {
							logger.warn("Unmatched erddef: ");
							logger.warn(file1 + ": " + file1Name
									+ " with type " + field1.getType());
							logger.warn(file2 + ": " + file2Name
									+ " with type " + field2.getType());
							break;
						}
					}
				}
			}

		}
	}
}
